]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
Add a configure option --enable-jhbuild-wrapper-script
authorColin Walters <walters@verbum.org>
Thu, 17 Feb 2011 22:07:13 +0000 (17:07 -0500)
committerColin Walters <walters@verbum.org>
Tue, 1 Mar 2011 14:51:06 +0000 (09:51 -0500)
The current gnome-shell.in script has a huge amount of
unnecessary complexity for the installed, normal case.  Fix
this by adding a configure option (defaulting to false) that
installs a simple, obvious wrapper script around mutter.

We do change the gnome-shell build setup to pass this option
by default for jhbuild.

https://bugzilla.gnome.org/show_bug.cgi?id=642084

.gitignore
configure.ac
src/Makefile.am
src/gnome-shell-installed.in [new file with mode: 0644]
src/gnome-shell-jhbuild.in [new file with mode: 0755]
src/gnome-shell.in [deleted file]
tools/build/gnome-shell.modules

index e01f1ea24b5ab22bac075b33597215e229cb0158..035bfce28ce4403a5c56c78eb7a03f7c6c5120b2 100644 (file)
@@ -42,6 +42,9 @@ src/Makefile
 src/Makefile.in
 src/gnomeshell-taskpanel
 src/gnome-shell
+src/gnome-shell-extension-tool
+src/gnome-shell-installed
+src/gnome-shell-jhbuild
 src/run-js-test
 src/test-recorder
 src/test-recorder.ogg
index 8155bae4ac756b93e909b965184f292bea48b045..1fb3bdd9a4c88a845394698978f2e33f7ed84205 100644 (file)
@@ -187,6 +187,24 @@ if test "$enable_compile_warnings" != no ; then
 fi
 changequote([,])dnl
 
+AC_ARG_ENABLE(jhbuild-wrapper-script,
+  AS_HELP_STRING([--jhbuild-wrapper-script=yes],[Make "gnome-shell" script work for jhbuild]),,enable_jhbuild_wrapper_script=no)
+AM_CONDITIONAL(USE_JHBUILD_WRAPPER_SCRIPT, test "x$enable_jhbuild_wrapper_script" = xyes)
+
+AC_MSG_CHECKING([for Ubuntu])
+if test -f /etc/ubuntu_version; then
+  enable_dynamic_mozjs_hack_default=yes
+  AC_MSG_RESULT([yes])
+else
+  enable_dynamic_mozjs_hack_default=no
+  AC_MSG_RESULT([no])
+fi
+
+AC_ARG_ENABLE(dynamic-mozjs-hack,
+  AS_HELP_STRING([--dynamic-mozjs-hack=no],[Look for libmozjs.so using pkg-config]),,enable_dynamic_mozjs_hack=$enable_dynamic_mozjs_hack_default)
+ENABLE_DYNAMIC_MOZJS_HACK=$enable_dynamic_mozjs_hack
+AC_SUBST(ENABLE_DYNAMIC_MOZJS_HACK)
+
 AC_PATH_PROG(mutter, [mutter])
 AC_SUBST(mutter)
 
index 170913b3546b045770643828a1a204158deb9bc2..c5fd0aa04a0c021e79d9bc71d1bb341a49dd5d05 100644 (file)
@@ -2,32 +2,44 @@ NULL =
 BUILT_SOURCES =
 CLEANFILES =
 EXTRA_DIST =
+bin_SCRIPTS =
 libexec_PROGRAMS =
 noinst_LTLIBRARIES =
 noinst_PROGRAMS =
 
 .AUTOPARALLEL:
 
-generated_bin_scripts = gnome-shell gnome-shell-extension-tool
-
-bin_SCRIPTS = $(generated_bin_scripts)
+generated_bin_scripts = gnome-shell-installed gnome-shell-jhbuild gnome-shell-extension-tool
+bin_SCRIPTS += gnome-shell $(generated_bin_scripts)
 
 generated_script_substitutions = -e "s|@MUTTER_BIN_DIR[@]|$(MUTTER_BIN_DIR)|" \
            -e "s|@datadir[@]|$(datadir)|" \
            -e "s|@libexecdir[@]|$(libexecdir)|" \
            -e "s|@libdir[@]|$(libdir)|" \
            -e "s|@pkgdatadir[@]|$(pkgdatadir)|" \
+           -e "s|@ENABLE_DYNAMIC_MOZJS_HACK[@]|$(ENABLE_DYNAMIC_MOZJS_HACK)|" \
            -e "s|@PYTHON[@]|$(PYTHON)|" \
            -e "s|@VERSION[@]|$(VERSION)|" \
            -e "s|@sysconfdir[@]|$(sysconfdir)|"
 
-gnome-shell: gnome-shell.in
+gnome-shell-jhbuild: gnome-shell-jhbuild.in Makefile
+       $(AM_V_GEN) sed $(generated_script_substitutions) $< > $@.tmp && mv $@.tmp $@ && chmod a+x $@
+
+gnome-shell-installed: gnome-shell-installed.in Makefile
        $(AM_V_GEN) sed $(generated_script_substitutions) $< > $@.tmp && mv $@.tmp $@ && chmod a+x $@
 
-gnome-shell-extension-tool: gnome-shell-extension-tool.in
+gnome-shell-extension-tool: gnome-shell-extension-tool.in Makefile
        $(AM_V_GEN) sed $(generated_script_substitutions) $< > $@.tmp && mv $@.tmp $@ && chmod a+x $@
 
-CLEANFILES += $(generated_bin_scripts)
+if USE_JHBUILD_WRAPPER_SCRIPT
+gnome-shell: gnome-shell-jhbuild Makefile
+       cp $< $@.tmp && mv $@.tmp $@
+else
+gnome-shell: gnome-shell-installed Makefile
+       cp $< $@.tmp && mv $@.tmp $@
+endif
+
+CLEANFILES += gnome-shell $(generated_bin_scripts)
 EXTRA_DIST += $(generated_bin_scripts:=.in)
 
 include Makefile-gdmuser.am
diff --git a/src/gnome-shell-installed.in b/src/gnome-shell-installed.in
new file mode 100644 (file)
index 0000000..3e98e41
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/bash
+# gnome-shell is a plugin for mutter; start mutter with the right
+# options.
+
+# About the value of NO_GAIL and NO_AT_BRIDGE: If a11y is enabled,
+# gtk_init() will normally load gail and at-bridge. But we don't
+# want at-bridge to be loaded until after clutter is initialized
+# (which mutter does after initializing gtk) and we don't want
+# gail to be loaded at all. So set these flags.  shell_a11y_init()
+# will clear them so they don't get passed to gnome-shell's
+# children.
+export NO_GAIL=1
+export NO_AT_BRIDGE=1
+
+# FIXME - Add gjs API to set this stuff and don't depend on the
+# environment.  These propagate to child processes.
+export GJS_DEBUG_OUTPUT='stderr'
+# By default only let gjs show errors and things that are explicitly
+# logged via log() from javascript
+export GJS_DEBUG_TOPICS='JS ERROR;JS LOG'
+
+if test -z "$MUTTER_PLUGINS"; then
+  MUTTER_PLUGINS=libgnome-shell
+fi
+
+# Work around Ubuntu xulrunner bug,
+# http://bugzilla.gnome.org/show_bug.cgi?id=573413
+if test x@ENABLE_DYNAMIC_MOZJS_HACK@ = xyes; then
+    sdkdir=$(pkg-config --variable=sdkdir mozilla-js)
+    if test -n "${sdkdir}"; then
+      mozjs_libdir=$(echo "$sdkdir" | sed -e s,'-\(sdk\|devel\)',,)
+      if test -n "$LD_LIBRARY_PATH"; then
+         LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$mozjs_libdir
+      else
+         LD_LIBRARY_PATH=$mozjs_libdir
+      fi
+      export LD_LIBRARY_PATH
+   fi
+fi
+
+exec mutter --mutter-plugins=$MUTTER_PLUGINS "$@"
diff --git a/src/gnome-shell-jhbuild.in b/src/gnome-shell-jhbuild.in
new file mode 100755 (executable)
index 0000000..bca0e32
--- /dev/null
@@ -0,0 +1,540 @@
+#!@PYTHON@
+# -*- mode: Python; indent-tabs-mode: nil; -*-
+
+import atexit
+import datetime
+import dbus
+from dbus.mainloop.glib import DBusGMainLoop
+import gobject
+try:
+    import json
+except ImportError:
+    try:
+        import simplejson as json
+    except ImportError:
+        json = None
+import optparse
+import os
+import random
+import re
+import shutil
+import signal
+import subprocess
+import sys
+import tempfile
+import termios
+import time
+import errno
+
+def show_version(option, opt_str, value, parser):
+    print "GNOME Shell @VERSION@"
+    sys.exit()
+
+def get_running_session_environs():
+    wanted_environment = ['DBUS_SESSION_BUS_ADDRESS', 'DISPLAY', 'XDG_DATA_DIRS',
+                          'XAUTHORITY', 'XDG_SESSION_COOKIE', 'ORBIT_SOCKETDIR',
+                          'SESSION_MANAGER']
+    num_re = re.compile('^[0-9]+$')
+    myuid = os.getuid()
+    if not os.path.isdir('/proc'):
+        return {}
+    for filename in os.listdir('/proc'):
+        if not num_re.match(filename):
+            continue
+        piddir = '/proc/' + filename
+        try:
+            stat = os.stat(piddir)
+        except OSError, e:
+            continue
+        if not stat.st_uid == myuid:
+            continue
+        try:
+            f = open(piddir + "/cmdline")
+            command = f.read()
+            f.close()
+        except IOError, e:
+            continue
+        # /proc/cmdline is separated and terminated by NULs
+        command = command.split("\x00")[0]
+        command = os.path.basename(command)
+        if command != 'gnome-session':
+            continue
+        try:
+            f = open(os.path.join(piddir, 'environ'))
+        except OSError, e:
+            continue
+        environ_data = f.read()
+        f.close()
+        # There's a trailing null at the last one, so remove the
+        # empty string
+        environs = environ_data.split('\0')[:-1]
+        # Rumor has it the presence of just FOO (instead of FOO=bar)
+        # represents a deleted environment variable
+        environs = filter(lambda x: '=' in x, environs)
+        # Turn it into a dictionary
+        environs = dict(map(lambda x: x.split('=', 1), environs))
+        result = {}
+        for key in wanted_environment:
+            if key in environs:
+                result[key] = environs[key]
+        return result
+
+def start_dconf_await_service():
+    DCONF_NAME = 'ca.desrt.dconf'
+
+    dbus_loop = DBusGMainLoop()
+    bus = dbus.SessionBus(mainloop=dbus_loop)
+
+    # See if the service is already running or normal D-Bus activation works
+    need_manual_activate = False
+    try:
+        dconf_proxy = bus.get_object(DCONF_NAME, '/')
+        dconf_proxy.Ping(dbus_interface='org.freedesktop.DBus.Peer')
+    except dbus.exceptions.DBusException, e:
+        if e.get_dbus_name() == 'org.freedesktop.DBus.Error.ServiceUnknown':
+            need_manual_activate = True
+        else:
+            raise e
+
+    if not need_manual_activate:
+        return
+
+    # At this point, it looks like we just have a jhbuild install
+    # of dconf, not known to the session dbus-daemon, so we start
+    # it manually and wait for it to join the bus
+
+    print "Starting dconf-service... ",
+    sys.stdout.flush()
+
+    # dconf is linked without libtool, so unlike other GNOME modules,
+    # won't have an embedded rpath for its library directory.
+    env = dict(os.environ)
+    if 'LD_LIBRARY_PATH' in env and env['LD_LIBRARY_PATH']:
+        ld_library_path = '@libdir@:' + env['LD_LIBRARY_PATH']
+    else:
+        ld_library_path = '@libdir@'
+    env['LD_LIBRARY_PATH'] = ld_library_path
+
+    dconf_path = os.path.join('@libexecdir@', 'dconf-service')
+    try:
+        subprocess.Popen([dconf_path, '--keep-alive'], env=env)
+    except OSError, e:
+        print "\nFailed to start %s: %s" % (dconf_path, e)
+        sys.exit(1)
+
+    bus_proxy = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
+    bus_iface = dbus.Interface(bus_proxy, 'org.freedesktop.DBus')
+
+    loop = gobject.MainLoop()
+
+    def on_name_owner_changed(name, prev_owner, new_owner):
+        if not (name == DCONF_NAME and new_owner != ''):
+            return
+        print "started"
+        loop.quit()
+        return
+    bus_iface.connect_to_signal('NameOwnerChanged', on_name_owner_changed)
+
+    def on_timeout():
+        print "\nFailed to start %s: timed out" % (dconf_path,)
+        sys.exit(1)
+    gobject.timeout_add_seconds(7, on_timeout)
+
+    loop.run()
+
+def start_shell(perf_output=None):
+    bin_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
+    if os.path.exists(os.path.join(bin_dir, 'gnome-shell.in')):
+        running_from_source_tree = True
+        top_dir = os.path.dirname(bin_dir)
+        plugin = os.path.join(top_dir, 'src', 'libgnome-shell.la')
+        typelib_dir = os.path.join(top_dir, "src")
+        js_dir = os.path.join(top_dir, "js")
+        data_dir = os.path.join(top_dir, "data")
+    else:
+        running_from_source_tree = False
+        plugin = 'libgnome-shell'
+        js_dir = os.path.join('@pkgdatadir@', 'js')
+
+    # Set up environment
+    env = dict(os.environ)
+    # TODO: Fix this, since nothing prevents it from propagating to child
+    # processes.  Why is it even here?
+    env.update({'GNOME_DISABLE_CRASH_DIALOG' : '1'})
+    # This stuff should really should only happen when running
+    # uninstalled, i.e. it should be in the conditional
+    # below. Otherwise it's just a bad reimplementation of "jhbuild
+    # run".  See bug #642084
+    env.update({'GNOME_SHELL_JS'      : js_dir,
+                'PATH'                : '@MUTTER_BIN_DIR@:' + os.environ.get('PATH', ''),
+                'XDG_CONFIG_DIRS'     : '@sysconfdir@/xdg:' + (os.environ.get('XDG_CONFIG_DIRS') or '/etc/xdg'),
+                'XDG_DATA_DIRS'       : '@datadir@:' + (os.environ.get('XDG_DATA_DIRS') or '/usr/local/share:/usr/share')})
+    if running_from_source_tree:
+        if os.environ.has_key('GI_TYPELIB_PATH'):
+            typelib_dir = typelib_dir + ":" + os.environ.get('GI_TYPELIB_PATH')
+        env.update({'GNOME_SHELL_BINDIR' : bin_dir,
+                    'GNOME_SHELL_DATADIR'  : data_dir,
+                    'GI_TYPELIB_PATH'      : typelib_dir,
+                    'GSETTINGS_SCHEMA_DIR' : data_dir })
+    else:
+        # This is just broken to set in the installed case; see bug #642084
+        env.update({'GSETTINGS_SCHEMA_DIR' : os.path.join('@datadir@', 'glib-2.0', 'schemas')})
+
+    # Also plain broken to set in the normal installed case
+    jhbuild_gconf_source = os.path.join('@sysconfdir@', 'gconf/2/path.jhbuild')
+    if os.path.exists(jhbuild_gconf_source):
+        env['GCONF_DEFAULT_SOURCE_PATH'] = jhbuild_gconf_source
+
+    if options.perf is not None:
+        env['SHELL_PERF_MODULE'] = options.perf
+
+    if perf_output is not None:
+        env['SHELL_PERF_OUTPUT'] = perf_output
+
+    if options.debug:
+        debug_command = options.debug_command.split()
+        args = list(debug_command)
+    else:
+        args = []
+
+    if running_from_source_tree:
+        env['MUTTER_PLUGINS'] = plugin
+    args.append(os.path.join(bin_dir, 'gnome-shell-installed'))
+    if options.replace:
+        args.append('--replace')
+    if options.sync:
+        args.append('--sync')
+    return subprocess.Popen(args, env=env)
+
+def run_shell(perf_output=None):
+    if options.debug:
+        # Record initial terminal state so we can reset it to that
+        # later, in case we kill gdb at a bad time
+        termattrs = termios.tcgetattr(0);
+
+    normal_exit = False
+
+    if options.verbose:
+        print "Starting shell"
+
+    try:
+        shell = start_shell(perf_output=perf_output)
+
+        # Wait for shell to exit
+        if options.verbose:
+            print "Waiting for shell to exit"
+        shell.wait()
+
+    except KeyboardInterrupt, e:
+        try:
+            os.kill(shell.pid, signal.SIGKILL)
+        except:
+            pass
+        shell.wait()
+    finally:
+        if shell is None:
+            print "Failed to start shell"
+        elif shell.returncode == 0:
+            normal_exit = True
+            if options.verbose:
+                print "Shell exited normally"
+        elif shell.returncode < 0:
+            # Python has no mapping for strsignal; not worth using
+            # ctypes for this.
+            print "Shell killed with signal %d" % - shell.returncode
+        else:
+            # Normal reason here would be losing connection the X server
+            if options.verbose:
+                print "Shell exited with return code %d" % shell.returncode
+
+        if options.debug:
+            termios.tcsetattr(0, termios.TCSANOW, termattrs);
+
+    return normal_exit
+
+def upload_performance_report(report_text):
+    # Local imports to avoid impacting gnome-shell startup time
+    import base64
+    from ConfigParser import RawConfigParser
+    import hashlib
+    import hmac
+    import httplib
+    import urlparse
+    import urllib
+
+    try:
+        config_home = os.environ['XDG_CONFIG_HOME']
+    except KeyError:
+        config_home = None
+
+    if not config_home:
+        config_home = os.path.expanduser("~/.config")
+
+    config_file = os.path.join(config_home, "gnome-shell/perf.ini")
+
+    try:
+        config = RawConfigParser()
+        f = open(config_file)
+        config.readfp(f)
+        f.close()
+
+        base_url = config.get('upload', 'url')
+        system_name = config.get('upload', 'name')
+        secret_key = config.get('upload', 'key')
+    except Exception, e:
+        print "Can't read upload configuration from %s: %s" % (config_file, str(e))
+        sys.exit(1)
+
+    # Determine host, port and upload URL from provided data, we're
+    # a bit extra-careful about normalization since the URL is part
+    # of the signature.
+
+    split = urlparse.urlsplit(base_url)
+    scheme = split[0].lower()
+    netloc = split[1]
+    base_path = split[2]
+
+    m = re.match(r'^(.*?)(?::(\d+))?$', netloc)
+    if m.group(2):
+        host, port = m.group(1), int(m.group(2))
+    else:
+        host, port = m.group(1), None
+
+    if scheme != "http":
+        print "'%s' is not a HTTP URL" % base_url
+        sys.exit(1)
+
+    if port is None:
+        port = 80
+
+    if base_path.endswith('/'):
+        base_path = base_path[:-1]
+
+    if port == 80:
+        normalized_base = "%s://%s%s" % (scheme, host, base_path)
+    else:
+        normalized_base = "%s://%s:%d%s" % (scheme, host, port, base_path)
+
+    upload_url = normalized_base + '/system/%s/upload' % system_name
+    upload_path = urlparse.urlsplit(upload_url)[2] # path portion
+
+    # Create signature based on upload URL and the report data
+
+    signature_data = 'POST&' + upload_url + "&&"
+    h = hmac.new(secret_key, digestmod=hashlib.sha1)
+    h.update(signature_data)
+    h.update(report_text)
+    signature = urllib.quote(base64.b64encode(h.digest()), "~")
+
+    headers = {
+        'User-Agent': 'gnome-shell',
+        'Content-Type': 'application/json',
+        'X-Shell-Signature': 'HMAC-SHA1 ' + signature
+    };
+
+    connection = httplib.HTTPConnection(host, port)
+    connection.request('POST', upload_path, report_text, headers)
+    response = connection.getresponse()
+
+    if response.status == 200:
+        print "Performance report upload succeeded"
+    else:
+        print "Performance report upload failed with status %d" % response.status
+        print response.read()
+
+def run_performance_test():
+    iters = options.perf_iters
+    if options.perf_warmup:
+        iters += 1
+
+    logs = []
+    metric_summaries = {}
+
+    for i in xrange(0, iters):
+        # We create an empty temporary file that the shell will overwrite
+        # with the contents.
+        handle, output_file = tempfile.mkstemp(".json", "gnome-shell-perf.")
+        os.close(handle)
+
+        # Run the performance test and collect the output as JSON
+        normal_exit = False
+        try:
+            normal_exit = run_shell(perf_output=output_file)
+        finally:
+            if not normal_exit:
+                os.remove(output_file)
+
+        if not normal_exit:
+            return False
+
+        try:
+            f = open(output_file)
+            output = json.load(f)
+            f.close()
+        finally:
+            os.remove(output_file)
+
+        # Grab the event definitions and monitor layout the first time around
+        if i == 0:
+            events = output['events']
+            monitors = output['monitors']
+
+        if options.perf_warmup and i == 0:
+            continue
+
+        for metric in output['metrics']:
+            name = metric['name']
+            if not name in metric_summaries:
+                summary = {}
+                summary['description'] = metric['description']
+                summary['units'] = metric['units']
+                summary['values'] = []
+                metric_summaries[name] = summary
+            else:
+                summary = metric_summaries[name]
+
+            summary['values'].append(metric['value'])
+
+        logs.append(output['log'])
+
+    if options.perf_output or options.perf_upload:
+        # Write a complete report, formatted as JSON. The Javascript/C code that
+        # generates the individual reports we are summarizing here is very careful
+        # to format them nicely, but we just dump out a compressed no-whitespace
+        # version here for simplicity. Using json.dump(indent=0) doesn't real
+        # improve the readability of the output much.
+        report = {
+            'date': datetime.datetime.utcnow().isoformat() + 'Z',
+            'events': events,
+            'monitors': monitors,
+            'metrics': metric_summaries,
+            'logs': logs
+        }
+
+        # Add the Git revision if available
+        bin_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
+        if os.path.exists(os.path.join(bin_dir, 'gnome-shell.in')):
+            top_dir = os.path.dirname(bin_dir)
+            git_dir = os.path.join(top_dir, '.git')
+            if os.path.exists(git_dir):
+                env = dict(os.environ)
+                env['GIT_DIR'] = git_dir
+                revision = subprocess.Popen(['git', 'rev-parse', 'HEAD'],
+                                            env=env,
+                                            stdout=subprocess.PIPE).communicate()[0].strip()
+                report['revision'] = revision
+
+        if options.perf_output:
+            f = open(options.perf_output, 'w')
+            json.dump(report, f)
+            f.close()
+
+        if options.perf_upload:
+            upload_performance_report(json.dumps(report))
+    else:
+        # Write a human readable summary
+        print '------------------------------------------------------------';
+        for metric in sorted(metric_summaries.keys()):
+            summary = metric_summaries[metric]
+            print "#", summary['description']
+            print metric, ", ".join((str(x) for x in summary['values']))
+        print '------------------------------------------------------------';
+
+    return True
+
+def restore_gnome():
+    # Do imports lazily to save time and memory
+    import gio
+    import gconf
+
+    # We don't want to start the new gnome-panel in the current
+    # directory; $HOME is better for stuff launched from it
+    os.chdir(os.path.expanduser("~"))
+
+    def launch_component(gconf_path):
+        client = gconf.client_get_default()
+        component = client.get_string(gconf_path)
+
+        if component == None or component == "":
+            return
+
+        # See gnome-session/gsm-util.c:gsm_util_find_desktop_file_for_app_name()
+        # The one difference is that we don't search the autostart directories,
+        # and just search normal application search path. (Gio doesnt' know
+        # how to search the autostart dirs, so we'd have to do that ourselves.)
+        appinfo = None
+        try:
+            appinfo = gio.unix.DesktopAppInfo(component + ".desktop")
+        except:
+            try:
+                appinfo = gio.unix.DesktopAppInfo("gnome-" + component + ".desktop")
+            except:
+                pass
+
+        if appinfo:
+            appinfo.launch()
+
+    launch_component("/desktop/gnome/session/required_components/windowmanager")
+    launch_component("/desktop/gnome/session/required_components/panel")
+
+# Main program
+
+parser = optparse.OptionParser()
+parser.add_option("-r", "--replace", action="store_true",
+                  help="Replace the running metacity/gnome-panel")
+parser.add_option("-g", "--debug", action="store_true",
+                  help="Run under a debugger")
+parser.add_option("", "--debug-command", metavar="COMMAND",
+                  help="Command to use for debugging (defaults to 'gdb --args')")
+parser.add_option("-v", "--verbose", action="store_true")
+parser.add_option("", "--sync", action="store_true")
+parser.add_option("", "--perf", metavar="PERF_MODULE",
+                 help="Specify the name of a performance module to run")
+parser.add_option("", "--perf-iters", type="int", metavar="ITERS",
+                 help="Numbers of iterations of performance module to run",
+                  default=1)
+parser.add_option("", "--perf-warmup", action="store_true",
+                 help="Run a dry run before performance tests")
+parser.add_option("", "--perf-output", metavar="OUTPUT_FILE",
+                 help="Output file to write performance report")
+parser.add_option("", "--perf-upload", action="store_true",
+                 help="Upload performance report to server")
+parser.add_option("", "--version", action="callback", callback=show_version,
+                  help="Display version and exit")
+
+options, args = parser.parse_args()
+
+if args:
+    parser.print_usage()
+    sys.exit(1)
+
+if options.perf and json is None:
+    print 'The Python simplejson module is required for performance tests'
+    sys.exit(1)
+
+# Handle ssh logins
+if 'DISPLAY' not in os.environ:
+    running_env = get_running_session_environs()
+    os.environ.update(running_env)
+
+if options.debug_command:
+    options.debug = True
+elif options.debug:
+    options.debug_command = "gdb --args"
+
+# We only respawn the previous environment on abnormal exit;
+# for a clean exit, we assume that gnome-shell was replaced with
+# something else.
+normal_exit = False
+
+# Make sure dconf daemon is running
+start_dconf_await_service()
+
+try:
+    if options.perf:
+        normal_exit = run_performance_test()
+    else:
+        normal_exit = run_shell()
+finally:
+    if options.replace and (options.perf or not normal_exit):
+        restore_gnome()
diff --git a/src/gnome-shell.in b/src/gnome-shell.in
deleted file mode 100755 (executable)
index 984abc6..0000000
+++ /dev/null
@@ -1,565 +0,0 @@
-#!@PYTHON@
-# -*- mode: Python; indent-tabs-mode: nil; -*-
-
-import atexit
-import datetime
-import dbus
-from dbus.mainloop.glib import DBusGMainLoop
-import gobject
-try:
-    import json
-except ImportError:
-    try:
-        import simplejson as json
-    except ImportError:
-        json = None
-import optparse
-import os
-import random
-import re
-import shutil
-import signal
-import subprocess
-import sys
-import tempfile
-import termios
-import time
-import errno
-
-def show_version(option, opt_str, value, parser):
-    print "GNOME Shell @VERSION@"
-    sys.exit()
-
-def get_running_session_environs():
-    wanted_environment = ['DBUS_SESSION_BUS_ADDRESS', 'DISPLAY', 'XDG_DATA_DIRS',
-                          'XAUTHORITY', 'XDG_SESSION_COOKIE', 'ORBIT_SOCKETDIR',
-                          'SESSION_MANAGER']
-    num_re = re.compile('^[0-9]+$')
-    myuid = os.getuid()
-    if not os.path.isdir('/proc'):
-        return {}
-    for filename in os.listdir('/proc'):
-        if not num_re.match(filename):
-            continue
-        piddir = '/proc/' + filename
-        try:
-            stat = os.stat(piddir)
-        except OSError, e:
-            continue
-        if not stat.st_uid == myuid:
-            continue
-        try:
-            f = open(piddir + "/cmdline")
-            command = f.read()
-            f.close()
-        except IOError, e:
-            continue
-        # /proc/cmdline is separated and terminated by NULs
-        command = command.split("\x00")[0]
-        command = os.path.basename(command)
-        if command != 'gnome-session':
-            continue
-        try:
-            f = open(os.path.join(piddir, 'environ'))
-        except OSError, e:
-            continue
-        environ_data = f.read()
-        f.close()
-        # There's a trailing null at the last one, so remove the
-        # empty string
-        environs = environ_data.split('\0')[:-1]
-        # Rumor has it the presence of just FOO (instead of FOO=bar)
-        # represents a deleted environment variable
-        environs = filter(lambda x: '=' in x, environs)
-        # Turn it into a dictionary
-        environs = dict(map(lambda x: x.split('=', 1), environs))
-        result = {}
-        for key in wanted_environment:
-            if key in environs:
-                result[key] = environs[key]
-        return result
-
-def start_dconf_await_service():
-    DCONF_NAME = 'ca.desrt.dconf'
-
-    dbus_loop = DBusGMainLoop()
-    bus = dbus.SessionBus(mainloop=dbus_loop)
-
-    # See if the service is already running or normal D-Bus activation works
-    need_manual_activate = False
-    try:
-        dconf_proxy = bus.get_object(DCONF_NAME, '/')
-        dconf_proxy.Ping(dbus_interface='org.freedesktop.DBus.Peer')
-    except dbus.exceptions.DBusException, e:
-        if e.get_dbus_name() == 'org.freedesktop.DBus.Error.ServiceUnknown':
-            need_manual_activate = True
-        else:
-            raise e
-
-    if not need_manual_activate:
-        return
-
-    # At this point, it looks like we just have a jhbuild install
-    # of dconf, not known to the session dbus-daemon, so we start
-    # it manually and wait for it to join the bus
-
-    print "Starting dconf-service... ",
-    sys.stdout.flush()
-
-    # dconf is linked without libtool, so unlike other GNOME modules,
-    # won't have an embedded rpath for its library directory.
-    env = dict(os.environ)
-    if 'LD_LIBRARY_PATH' in env and env['LD_LIBRARY_PATH']:
-        ld_library_path = '@libdir@:' + env['LD_LIBRARY_PATH']
-    else:
-        ld_library_path = '@libdir@'
-    env['LD_LIBRARY_PATH'] = ld_library_path
-
-    dconf_path = os.path.join('@libexecdir@', 'dconf-service')
-    try:
-        subprocess.Popen([dconf_path, '--keep-alive'], env=env)
-    except OSError, e:
-        print "\nFailed to start %s: %s" % (dconf_path, e)
-        sys.exit(1)
-
-    bus_proxy = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
-    bus_iface = dbus.Interface(bus_proxy, 'org.freedesktop.DBus')
-
-    loop = gobject.MainLoop()
-
-    def on_name_owner_changed(name, prev_owner, new_owner):
-        if not (name == DCONF_NAME and new_owner != ''):
-            return
-        print "started"
-        loop.quit()
-        return
-    bus_iface.connect_to_signal('NameOwnerChanged', on_name_owner_changed)
-
-    def on_timeout():
-        print "\nFailed to start %s: timed out" % (dconf_path,)
-        sys.exit(1)
-    gobject.timeout_add_seconds(7, on_timeout)
-
-    loop.run()
-
-def start_shell(perf_output=None):
-    bin_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
-    if os.path.exists(os.path.join(bin_dir, 'gnome-shell.in')):
-        running_from_source_tree = True
-        top_dir = os.path.dirname(bin_dir)
-        plugin = os.path.join(top_dir, 'src', 'libgnome-shell.la')
-        typelib_dir = os.path.join(top_dir, "src")
-        js_dir = os.path.join(top_dir, "js")
-        data_dir = os.path.join(top_dir, "data")
-    else:
-        running_from_source_tree = False
-        plugin = 'libgnome-shell'
-        js_dir = os.path.join('@pkgdatadir@', 'js')
-
-    # Set up environment
-
-    # About the value of NO_GAIL and NO_AT_BRIDGE: If a11y is enabled,
-    # gtk_init() will normally load gail and at-bridge. But we don't
-    # want at-bridge to be loaded until after clutter is initialized
-    # (which mutter does after initializing gtk) and we don't want
-    # gail to be loaded at all. So set these flags.  shell_a11y_init()
-    # will clear them so they don't get passed to gnome-shell's
-    # children.
-
-    env = dict(os.environ)
-    env.update({'GNOME_SHELL_JS'      : js_dir,
-                'PATH'                : '@MUTTER_BIN_DIR@:' + os.environ.get('PATH', ''),
-                'XDG_CONFIG_DIRS'     : '@sysconfdir@/xdg:' + (os.environ.get('XDG_CONFIG_DIRS') or '/etc/xdg'),
-                'XDG_DATA_DIRS'       : '@datadir@:' + (os.environ.get('XDG_DATA_DIRS') or '/usr/local/share:/usr/share'),
-                'GNOME_DISABLE_CRASH_DIALOG' : '1',
-                'NO_GAIL'             : '1',
-                'NO_AT_BRIDGE'        : '1'})
-
-    if running_from_source_tree:
-        if os.environ.has_key('GI_TYPELIB_PATH'):
-            typelib_dir = typelib_dir + ":" + os.environ.get('GI_TYPELIB_PATH')
-        env.update({'GNOME_SHELL_BINDIR' : bin_dir,
-                    'GNOME_SHELL_DATADIR'  : data_dir,
-                    'GI_TYPELIB_PATH'      : typelib_dir,
-                    'GSETTINGS_SCHEMA_DIR' : data_dir })
-    else:
-        env.update({'GSETTINGS_SCHEMA_DIR' : os.path.join('@datadir@', 'glib-2.0', 'schemas')})
-
-    jhbuild_gconf_source = os.path.join('@sysconfdir@', 'gconf/2/path.jhbuild')
-    if os.path.exists(jhbuild_gconf_source):
-        env['GCONF_DEFAULT_SOURCE_PATH'] = jhbuild_gconf_source
-
-    # Work around Ubuntu xulrunner bug,
-    # http://bugzilla.gnome.org/show_bug.cgi?id=573413
-    pkgconfig = subprocess.Popen(['pkg-config', '--variable=sdkdir', 'mozilla-js'],
-                                 stdout=subprocess.PIPE)
-    mozjs_sdkdir = pkgconfig.communicate()[0].strip()
-    pkgconfig.wait()
-    if pkgconfig.returncode == 0:
-        mozjs_libdir = re.sub('-(sdk|devel)', '', mozjs_sdkdir)
-        if os.path.exists(mozjs_libdir + '/libmozjs.so'):
-            if 'LD_LIBRARY_PATH' in env and env['LD_LIBRARY_PATH']:
-                ld_library_path = env['LD_LIBRARY_PATH'] + ':' + mozjs_libdir
-            else:
-                ld_library_path = mozjs_libdir
-            env['LD_LIBRARY_PATH'] = ld_library_path
-
-    # Log everything to stderr (make stderr our "log file")
-    env['GJS_DEBUG_OUTPUT'] = 'stderr'
-
-    if not options.verbose:
-        # Unless verbose() is specified, only let gjs show errors and
-        # things that are explicitly logged via log() from javascript
-        env['GJS_DEBUG_TOPICS'] = 'JS ERROR;JS LOG'
-
-    if options.perf is not None:
-        env['SHELL_PERF_MODULE'] = options.perf
-
-    if perf_output is not None:
-        env['SHELL_PERF_OUTPUT'] = perf_output
-
-    if options.debug:
-        debug_command = options.debug_command.split()
-        args = list(debug_command)
-    else:
-        args = []
-        
-    args.extend(['mutter', '--mutter-plugins=' + plugin])
-    if options.replace:
-        args.append('--replace')
-    if options.sync:
-        args.append('--sync')
-    return subprocess.Popen(args, env=env)
-
-def run_shell(perf_output=None):
-    if options.debug:
-        # Record initial terminal state so we can reset it to that
-        # later, in case we kill gdb at a bad time
-        termattrs = termios.tcgetattr(0);
-
-    normal_exit = False
-
-    if options.verbose:
-        print "Starting shell"
-
-    try:
-        shell = start_shell(perf_output=perf_output)
-
-        # Wait for shell to exit
-        if options.verbose:
-            print "Waiting for shell to exit"
-        shell.wait()
-
-    except KeyboardInterrupt, e:
-        try:
-            os.kill(shell.pid, signal.SIGKILL)
-        except:
-            pass
-        shell.wait()
-    finally:
-        if shell is None:
-            print "Failed to start shell"
-        elif shell.returncode == 0:
-            normal_exit = True
-            if options.verbose:
-                print "Shell exited normally"
-        elif shell.returncode < 0:
-            # Python has no mapping for strsignal; not worth using
-            # ctypes for this.
-            print "Shell killed with signal %d" % - shell.returncode
-        else:
-            # Normal reason here would be losing connection the X server
-            if options.verbose:
-                print "Shell exited with return code %d" % shell.returncode
-
-        if options.debug:
-            termios.tcsetattr(0, termios.TCSANOW, termattrs);
-
-    return normal_exit
-
-def upload_performance_report(report_text):
-    # Local imports to avoid impacting gnome-shell startup time
-    import base64
-    from ConfigParser import RawConfigParser
-    import hashlib
-    import hmac
-    import httplib
-    import urlparse
-    import urllib
-
-    try:
-        config_home = os.environ['XDG_CONFIG_HOME']
-    except KeyError:
-        config_home = None
-
-    if not config_home:
-        config_home = os.path.expanduser("~/.config")
-
-    config_file = os.path.join(config_home, "gnome-shell/perf.ini")
-
-    try:
-        config = RawConfigParser()
-        f = open(config_file)
-        config.readfp(f)
-        f.close()
-
-        base_url = config.get('upload', 'url')
-        system_name = config.get('upload', 'name')
-        secret_key = config.get('upload', 'key')
-    except Exception, e:
-        print "Can't read upload configuration from %s: %s" % (config_file, str(e))
-        sys.exit(1)
-
-    # Determine host, port and upload URL from provided data, we're
-    # a bit extra-careful about normalization since the URL is part
-    # of the signature.
-
-    split = urlparse.urlsplit(base_url)
-    scheme = split[0].lower()
-    netloc = split[1]
-    base_path = split[2]
-
-    m = re.match(r'^(.*?)(?::(\d+))?$', netloc)
-    if m.group(2):
-        host, port = m.group(1), int(m.group(2))
-    else:
-        host, port = m.group(1), None
-
-    if scheme != "http":
-        print "'%s' is not a HTTP URL" % base_url
-        sys.exit(1)
-
-    if port is None:
-        port = 80
-
-    if base_path.endswith('/'):
-        base_path = base_path[:-1]
-
-    if port == 80:
-        normalized_base = "%s://%s%s" % (scheme, host, base_path)
-    else:
-        normalized_base = "%s://%s:%d%s" % (scheme, host, port, base_path)
-
-    upload_url = normalized_base + '/system/%s/upload' % system_name
-    upload_path = urlparse.urlsplit(upload_url)[2] # path portion
-
-    # Create signature based on upload URL and the report data
-
-    signature_data = 'POST&' + upload_url + "&&"
-    h = hmac.new(secret_key, digestmod=hashlib.sha1)
-    h.update(signature_data)
-    h.update(report_text)
-    signature = urllib.quote(base64.b64encode(h.digest()), "~")
-
-    headers = {
-        'User-Agent': 'gnome-shell',
-        'Content-Type': 'application/json',
-        'X-Shell-Signature': 'HMAC-SHA1 ' + signature
-    };
-
-    connection = httplib.HTTPConnection(host, port)
-    connection.request('POST', upload_path, report_text, headers)
-    response = connection.getresponse()
-
-    if response.status == 200:
-        print "Performance report upload succeeded"
-    else:
-        print "Performance report upload failed with status %d" % response.status
-        print response.read()
-
-def run_performance_test():
-    iters = options.perf_iters
-    if options.perf_warmup:
-        iters += 1
-
-    logs = []
-    metric_summaries = {}
-
-    for i in xrange(0, iters):
-        # We create an empty temporary file that the shell will overwrite
-        # with the contents.
-        handle, output_file = tempfile.mkstemp(".json", "gnome-shell-perf.")
-        os.close(handle)
-
-        # Run the performance test and collect the output as JSON
-        normal_exit = False
-        try:
-            normal_exit = run_shell(perf_output=output_file)
-        finally:
-            if not normal_exit:
-                os.remove(output_file)
-
-        if not normal_exit:
-            return False
-
-        try:
-            f = open(output_file)
-            output = json.load(f)
-            f.close()
-        finally:
-            os.remove(output_file)
-
-        # Grab the event definitions and monitor layout the first time around
-        if i == 0:
-            events = output['events']
-            monitors = output['monitors']
-
-        if options.perf_warmup and i == 0:
-            continue
-
-        for metric in output['metrics']:
-            name = metric['name']
-            if not name in metric_summaries:
-                summary = {}
-                summary['description'] = metric['description']
-                summary['units'] = metric['units']
-                summary['values'] = []
-                metric_summaries[name] = summary
-            else:
-                summary = metric_summaries[name]
-
-            summary['values'].append(metric['value'])
-
-        logs.append(output['log'])
-
-    if options.perf_output or options.perf_upload:
-        # Write a complete report, formatted as JSON. The Javascript/C code that
-        # generates the individual reports we are summarizing here is very careful
-        # to format them nicely, but we just dump out a compressed no-whitespace
-        # version here for simplicity. Using json.dump(indent=0) doesn't real
-        # improve the readability of the output much.
-        report = {
-            'date': datetime.datetime.utcnow().isoformat() + 'Z',
-            'events': events,
-            'monitors': monitors,
-            'metrics': metric_summaries,
-            'logs': logs
-        }
-
-        # Add the Git revision if available
-        bin_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
-        if os.path.exists(os.path.join(bin_dir, 'gnome-shell.in')):
-            top_dir = os.path.dirname(bin_dir)
-            git_dir = os.path.join(top_dir, '.git')
-            if os.path.exists(git_dir):
-                env = dict(os.environ)
-                env['GIT_DIR'] = git_dir
-                revision = subprocess.Popen(['git', 'rev-parse', 'HEAD'],
-                                            env=env,
-                                            stdout=subprocess.PIPE).communicate()[0].strip()
-                report['revision'] = revision
-
-        if options.perf_output:
-            f = open(options.perf_output, 'w')
-            json.dump(report, f)
-            f.close()
-
-        if options.perf_upload:
-            upload_performance_report(json.dumps(report))
-    else:
-        # Write a human readable summary
-        print '------------------------------------------------------------';
-        for metric in sorted(metric_summaries.keys()):
-            summary = metric_summaries[metric]
-            print "#", summary['description']
-            print metric, ", ".join((str(x) for x in summary['values']))
-        print '------------------------------------------------------------';
-
-    return True
-
-def restore_gnome():
-    # Do imports lazily to save time and memory
-    import gio
-    import gconf
-
-    # We don't want to start the new gnome-panel in the current
-    # directory; $HOME is better for stuff launched from it
-    os.chdir(os.path.expanduser("~"))
-
-    def launch_component(gconf_path):
-        client = gconf.client_get_default()
-        component = client.get_string(gconf_path)
-
-        if component == None or component == "":
-            return
-
-        # See gnome-session/gsm-util.c:gsm_util_find_desktop_file_for_app_name()
-        # The one difference is that we don't search the autostart directories,
-        # and just search normal application search path. (Gio doesnt' know
-        # how to search the autostart dirs, so we'd have to do that ourselves.)
-        appinfo = None
-        try:
-            appinfo = gio.unix.DesktopAppInfo(component + ".desktop")
-        except:
-            try:
-                appinfo = gio.unix.DesktopAppInfo("gnome-" + component + ".desktop")
-            except:
-                pass
-
-        if appinfo:
-            appinfo.launch()
-
-    launch_component("/desktop/gnome/session/required_components/windowmanager")
-    launch_component("/desktop/gnome/session/required_components/panel")
-
-# Main program
-
-parser = optparse.OptionParser()
-parser.add_option("-r", "--replace", action="store_true",
-                  help="Replace the running metacity/gnome-panel")
-parser.add_option("-g", "--debug", action="store_true",
-                  help="Run under a debugger")
-parser.add_option("", "--debug-command", metavar="COMMAND",
-                  help="Command to use for debugging (defaults to 'gdb --args')")
-parser.add_option("-v", "--verbose", action="store_true")
-parser.add_option("", "--sync", action="store_true")
-parser.add_option("", "--perf", metavar="PERF_MODULE",
-                 help="Specify the name of a performance module to run")
-parser.add_option("", "--perf-iters", type="int", metavar="ITERS",
-                 help="Numbers of iterations of performance module to run",
-                  default=1)
-parser.add_option("", "--perf-warmup", action="store_true",
-                 help="Run a dry run before performance tests")
-parser.add_option("", "--perf-output", metavar="OUTPUT_FILE",
-                 help="Output file to write performance report")
-parser.add_option("", "--perf-upload", action="store_true",
-                 help="Upload performance report to server")
-parser.add_option("", "--version", action="callback", callback=show_version,
-                  help="Display version and exit")
-
-options, args = parser.parse_args()
-
-if args:
-    parser.print_usage()
-    sys.exit(1)
-
-if options.perf and json is None:
-    print 'The Python simplejson module is required for performance tests'
-    sys.exit(1)
-
-# Handle ssh logins
-if 'DISPLAY' not in os.environ:
-    running_env = get_running_session_environs()
-    os.environ.update(running_env)
-
-if options.debug_command:
-    options.debug = True
-elif options.debug:
-    options.debug_command = "gdb --args"
-
-# We only respawn the previous environment on abnormal exit;
-# for a clean exit, we assume that gnome-shell was replaced with
-# something else.
-normal_exit = False
-
-# Make sure dconf daemon is running
-start_dconf_await_service()
-
-try:
-    if options.perf:
-        normal_exit = run_performance_test()
-    else:
-        normal_exit = run_shell()
-finally:
-    if options.replace and (options.perf or not normal_exit):
-        restore_gnome()
index 778db203faf9e5e9f689c00aff452a0324b65607..b32104ef5bff041ba422c5f779693af0e0ce35ca 100644 (file)
     </dependencies>
   </autotools>
 
-  <autotools id="gnome-shell">
+  <autotools id="gnome-shell" autogenargs="--enable-jhbuild-wrapper-script">
     <branch repo="git.gnome.org" module="gnome-shell"/>
     <dependencies>
         <dep package="gobject-introspection"/>